Skip to content

perf(agc): keep the cached address space for a read-only V# across two imports - #5428

Merged
oneandonlydean merged 3 commits into
boykopovar:mainfrom
alfalfa-star:perf/agc-keep-address-space-read-overlap
Oct 14, 2026
Merged

oneandonlydean merged 3 commits into
boykopovar:mainfrom
alfalfa-star:perf/agc-keep-address-space-read-overlap

Conversation

@alfalfa-star

Copy link
Copy Markdown
Contributor

Why

Kena: Bridge of Spirits (PPSA01802, UE4) spends most of its driver time rebuilding the resources of address-based draws once its first level loads. Most of those builds hit the cached address space, but about 70% of them then dissolve it. A read-only V# crosses the boundary between two adjacent registered ranges that are imported separately, for example 0x20163a0000+0x240000 over 0x20163a0000-0x20165c0000 and 0x20165c0000-0x2016650000. addDescriptorRegion sees a partial overlap with the space and calls dissolveSpace, which merges all of the space's ranges (about 9,000 in that scene) into the build. UploadPrepare then sorts and merges them, and UploadFinish and AddressRanges walk them, on every such draw.

What

  • A read-only descriptor region (AddReadable) that partially overlaps the space's ranges no longer dissolves the space, unless one of the overlapped ranges is an image mirror. The region is added to the build's own regions and copied, as it was after a dissolve. Its BDA table entry is read-only, as the merged copied region's was.
  • Writable descriptor regions, snapshots and mirror overlaps still dissolve the space, as before.

Tested

Linux (Arch, kernel 7.2), RADV RX 9070 XT, Release.

  • New spaceReadAcrossImportsTests in agc_driver_graphics: three 64 KiB ranges with a 128 KiB import window give two imports. A read-only V# across their boundary must bind the bytes of both ranges, keep both imports in the BDA table, and, on the second build, hit the cached space without a dissolve. It passes with the change. Without it, it fails with a read-only V# across two imports dissolved the cached address space.
  • Full ctest: 1070 of 1071 pass. agc_driver_tessellation segfaults on this machine on plain main as well.
  • Kena, on a local stack with other unmerged changes, two runs of the same build. I have no summary lines of main against this branch alone, and no trace attached; I can capture them on request. The comparison switched this change off together with a second local change (reusing draws whose read-only buffers were copied), so the numbers below are for both. Address-space dissolves drop from about 38 to 0 per 10 s, and the average number of regions in an address-based build from 225 to 3; those two come from this change. Graphics::Draw drops from 683 to 390 us per draw packet. Presents go from 10-21 to 81-89 per 10 s in the middle of the run, and from about 19 to 33-41 in the heaviest part.

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Unblocks: none (performance of PPSA01802)
  • GPUs tested: AMD Radeon RX 9070 XT, RADV Mesa 26.2.4, Arch Linux (kernel 7.2.9)
  • AI-assisted: yes

🤖 Generated with Claude Code

@github-actions github-actions Bot added the agc libSceAgc* label Oct 13, 2026
@oneandonlydean oneandonlydean self-assigned this Oct 13, 2026
@oneandonlydean

Copy link
Copy Markdown
Collaborator

Two things before this can go in:

  • Numbers for this change alone: the summary lines of main and of main plus this PR from the same scene, with the traces.
  • The copied read-only region now overlaps the space's live ranges. A writable V# that lies inside one of those ranges doesn't dissolve the space, so it binds the import while the read-only V# binds a copy of the same bytes (addDescriptorRegion, GuestBufferMemory.cpp:2477). On main both use the one merged region. Please keep the dissolve when a write range overlaps the copied region, or add a test that shows the two views stay coherent.

…o imports

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@oneandonlydean
oneandonlydean force-pushed the perf/agc-keep-address-space-read-overlap branch from ad05918 to 972ce12 Compare October 14, 2026 02:50
@oneandonlydean

Copy link
Copy Markdown
Collaborator

Rebased onto main to resolve the conflict in tests/BdaResources.cpp after #290; no other change.

…s a read-only V# copied across imports

A read-only V# that crosses two base regions is copied per build while the
space stays. A written V# overlapping that copy would bind the base region's
import while the read-only V# binds the copy of the same bytes. Dissolve the
space in that case (either order of the two), as without this branch, so both
share the one merged region.
@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.

Pull request Conflicting files (lines on main) Same exports Same new files
#3248 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp L392-393

@alfalfa-star

Copy link
Copy Markdown
Contributor Author

@oneandonlydean thanks for e5d6556 and fd2c300, the dissolve for a written V# over the copied read-only range and its test. That covers the coherence point.

On the numbers: I can't take a main capture of the Kena (PPSA01802) scene yet. Plain main (aa19278, this PR's base) aborts before the title scene, before the trace window opens:

[videoout] presentation failed: AGC graphics: shader buffer exceeds descriptor range limit
terminate called after throwing an instance of 'std::runtime_error'
  what():  AGC graphics: shader buffer exceeds descriptor range limit

It stops the same way with #5573 on top. My earlier numbers came from a local stack that skips draws which throw, which is why the description doesn't present them as main against this PR. I'm looking into the range-limit stop now. Once a base reaches the scene, I'll post the summary lines and traces of base and base plus this PR from the same session.

@oneandonlydean

Copy link
Copy Markdown
Collaborator

Pushed two commits on top so this can go in. If a written V# overlaps a read-only V# that is copied across two imports, the space now dissolves, in either order of the two, as it does on main without this branch. That way both bind the one merged region. If no written range overlaps, the space stays as before. The new spaceReadAcrossImportsWrittenTests in tests/BdaResources.cpp checks that the written and the read-only V# map the shared bytes through one buffer at matching offsets, and that the space dissolves. It fails on the previous head ("maps other bytes than it") and passes now. Full build is green on fd2c300.

One run of main + this PR, as an indication only (n=1, no main run from the same session to compare against): PPSA21564 first level, APS5_TRACE_FRAMES=4300:80, RTX 4090, NVIDIA 610.57.04, Linux, 3840x2160. Frame time p50 21.15 ms, p90 23.30 ms; GPU busy 14.7 ms per present. Gate phases: title 23.8, menu 20.3, level 27.0 fps, in line with recent main runs on this machine. The checkpoints look the same as on main.

This closes our earlier ask.

@oneandonlydean
oneandonlydean merged commit f74ec63 into boykopovar:main Oct 14, 2026
8 checks passed
@alfalfa-star
alfalfa-star deleted the perf/agc-keep-address-space-read-overlap branch October 14, 2026 06:35
@EagleBearerYS

Copy link
Copy Markdown
Contributor

Resident Evil Village (PPSA01556) stops on this change's path at the title:

[videoout] presentation failed: AGC graphics: guest buffer view 0x1f0494592c+0x1b2190 exceeds its GPU owner 0x1f04940000-0x1f04950000 (buffer 0, direct 1, mirror 0)

Since this PR, a read-only V# that partly overlaps the cached space's base gets a region of its own, so a build's own regions can overlap base regions. GuestBufferMemory::owner() still assumed they don't. For this 1.7 MB view it returned the base region of one 64 KiB mapping, and Descriptor refused the view. A dissolve after UploadPrepare reaches the same lookup during the first scene load. #5815 fixes both. Its description has the details, a test that fails on main with this message, and the runs.

Setup for the stop: main 23be5a0 with #5688 and #5703, plus local test commits listed in #5815. Windows 11, RTX 3070 Laptop, driver 617.42.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agc libSceAgc*

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants